#pragma once

#include "my_nvs.hpp"
#include <vector>
#include <functional>
#include <type_traits>
#include <sdkconfig.h>



using FieldBytes = int16_t;     // 结构体中字段字节数
using FieldCount = uint16_t;    // 用户结构体字段数量
enum FieldType {
    kNormal_1,      // 1字节常规数据，如char、int8_t
    kNormal_2,
    kNormal_4,
    kNormal_8,
    kString,        // std::string字符串
    kArray_Char,    // char[]字符串
    kArray_Blob,    // 字节数组，如int8_t[]
    kUnsupport
};
struct StructMetaData {
    FieldType   type;       // 字段类型
    FieldBytes  bytes;      // 字段所占字节数
    size_t      offset;     // 字段相对头部偏移
};
struct StructMeta {
    FieldCount                      field_count;    // 字段数量
    FieldBytes                      total_bytes;    // 结构总字节数
    std::vector<StructMetaData> 	data;           // 字段数据
};

// 元信息生成宏
#define DECLARE_META(StructType, ...) \
    StructMeta{ \
        static_cast<FieldCount>(sizeof((StructMetaData[]) { __VA_ARGS__ }) / sizeof(StructMetaData)), \
        static_cast<FieldBytes>(sizeof(StructType)), \
        std::vector<StructMetaData>{ __VA_ARGS__ } \
    }

#define FIELD(StructType, field) \
    StructMetaData{ \
        []() -> FieldType { \
            using TempType = decltype(std::declval<StructType>().field); \
            if constexpr (std::is_same_v<TempType, std::string> || \
                            std::is_same_v<TempType, const std::string>) { \
                return kString; \
            } else if constexpr (std::is_array_v<TempType>) { \
                using ElementType = std::remove_cv_t<std::remove_extent_t<TempType>>; \
                if constexpr (std::is_same_v<ElementType, char>) { \
                    return kArray_Char; \
                } else { \
                    return kArray_Blob; \
                } \
            } else { \
                constexpr size_t size = sizeof(decltype(std::declval<StructType>().field)); \
                if constexpr (size == 1) return kNormal_1; \
                if constexpr (size == 2) return kNormal_2; \
                if constexpr (size == 4) return kNormal_4; \
                if constexpr (size == 8) return kNormal_8; \
                return kUnsupport; \
            } \
        }(), \
        static_cast<FieldBytes>(sizeof(decltype(std::declval<StructType>().field))), \
        offsetof(StructType, field) \
    }


using BitSize = uint8_t;
using BitmapType = uint32_t;    // 位图类型（控制大小）---可使用数组扩展
using BitmapIndex = int32_t;

using HandleFunction = std::function<void(BitmapIndex,const void*)>;

/// @brief 用户元数据类,提供：加载、保存、修改、删除操作
class StorageManager {
public:
    StorageManager(const std::string& nspace, const std::string& prefix, const StructMeta& meta);
    ~StorageManager();

    BitmapIndex begin() const;
    BitmapIndex end() const;
    BitmapIndex next(const BitmapIndex i) const;


    // 格式化存储
    static esp_err_t   Format(const std::string& nspace, const std::string& prefix, const StructMeta& meta);
    esp_err_t   Clear();
    BitmapIndex Add(const void* addr);
    esp_err_t   Read(BitmapIndex index, void* addr);
    esp_err_t   Del(const BitmapIndex index);
    esp_err_t   Del(const BitmapType mask);
    // 提供一个按字段删除整个结构的API............
    esp_err_t   DifferWrite(const BitmapIndex, const void* old_ptr, const void* new_ptr);
    inline size_t GetSize() const { return space_; }
    inline size_t GetUsed() const { return used_; }
    inline esp_err_t   Commit() { return nvs_.commit(); }
    inline BitmapType IndexToBitmap(BitmapIndex i) const { return BitmapType(1) << i; }


private:
    inline bool IsFull() { return used_ == space_; }
    BitmapIndex GetFreeIndex();
    esp_err_t   ReadField(const std::string& key, FieldType field_type, void* data, FieldBytes bytes = 0);
    esp_err_t   WriteField(const std::string& key, FieldType field_type, const void* data, FieldBytes bytes = 0);

    MyNVS           nvs_;           // NVS对象
    size_t          used_;          // 结构化存储使用情况
    size_t          space_;         // 结构化存储空间大小
    std::string     prefix_;        // 键前缀（用于组织储存）
    BitmapType      bitmap_;        // 位图（用户指示存储位置）
    StructMeta      meta_;          // 用户结构元数据（用于引导数据存储）
};